package com.bignerdranch.android.sensorapplication;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;

import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.bignerdranch.android.sensorapplication.utils.FileRecord;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import Jama.Matrix;
import pub.devrel.easypermissions.EasyPermissions;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private SensorManager mSensorManager;
    private Sensor magneticSensor;
    private Sensor accelerometerSensor;
    private Sensor pressureSensor;
    private Sensor stepSensor;
    private Sensor detectSensor;
    private Sensor gravitySensor;
    private Sensor gyroscopeSensor;
    private Sensor orienSensor;
    private TextView ansText;
    private TextView showTime;
    private TextView stepText;
    private TextView gyroText;
    private TextView magneticMagnitude;
    private Timer mTimer;

    private boolean gravityStartFlag = false;

    private static final int RC_STORAGE_PERM = 123;
    private static final String[] NEED_PERMISSIONS =
            {Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.ACCESS_COARSE_LOCATION};

    private static final String PREFERENCES_NAME = "record_filename";

    private KalmanFilter mKalmanFilter;

    private Button startButton;
    private Button stopButton;
    private Button dataButton;

    private EditText actionEdit;
    private EditText typeEdit;
    private TextView accelerationText;
    private TextView magneticText;
    private TextView directionText;
    private TextView pressureText;
    private TextView showAllSensors;

    private int count = 0;
    private long timestamp;

    private TimerTask mTimerTask;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            count++;
            showTime.setText(String.valueOf(count));
        }
    };

    public static final String folder = Environment.getExternalStorageDirectory()
            .getPath() + "/sensor_records";
    private String fileName;
    private float geomagnetic[]=new float[3];
    private float orientation_values[]=new float[3];
    private float gravity[]=new float[3];
    private float accel[] = new float[3];

    // accelerometer and magnetometer based rotation matrix
    private float[] rotationMatrix = new float[9];
    
    private String direction;
//    private String getAction;
    private String newPath;

    //启动时是否从系统中获取已有的步数记录
    private boolean hasRecoed = false;
    //获取系统中已有的步数记录
    private int hasStepCount = 0;
    //上一次的步数
    private int previousStepCount = 0;

    private int steps;

    //当前传感器的值
    float gravityNew = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EasyPermissions.requestPermissions(this, "App需要读写SD卡以及位置的权限", RC_STORAGE_PERM, NEED_PERMISSIONS);

        File file=new File(folder);
        if(!file.exists()) {
            if (file.mkdir()) {
                Toast.makeText(this, "文件夹创建成功", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "错误，请检查文件夹读写权限", Toast.LENGTH_SHORT).show();
            }
        }

        initViews();

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        pressureSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
        stepSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
        detectSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
        gravitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
        gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
        orienSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(mSensorEventListener);
        }
    }

    private void initViews() {
        ansText = findViewById(R.id.res_text);
        showTime = findViewById(R.id.time_show);
        startButton = findViewById(R.id.start_record);
        stopButton = findViewById(R.id.stop_record);
        actionEdit = findViewById(R.id.action_value);
        typeEdit = findViewById(R.id.type_get);

        accelerationText = findViewById(R.id.acceleration_text);
        directionText = findViewById(R.id.device_direction);
        magneticText = findViewById(R.id.magnetic_text);
        pressureText = findViewById(R.id.device_pressure);
        dataButton = findViewById(R.id.info_submit);
        stepText = findViewById(R.id.step_count);
        gyroText = findViewById(R.id.gyro_text);
        showAllSensors = findViewById(R.id.show_all_sensors);
        magneticMagnitude = findViewById(R.id.magnetic_magnitude);

        startButton.setOnClickListener(this);
        stopButton.setOnClickListener(this);
        dataButton.setOnClickListener(this);
        showAllSensors.setOnClickListener(this);
    }

    private SensorEventListener mSensorEventListener = new SensorEventListener() {

        @Override
        public void onSensorChanged(SensorEvent event) {
            timestamp = System.currentTimeMillis();

            switch (event.sensor.getType()) {
                case Sensor.TYPE_ACCELEROMETER:
                    System.arraycopy(event.values, 0, accel, 0, 3);
                    onAccelerationChanged(event);
                    break;
                case Sensor.TYPE_MAGNETIC_FIELD:
                    onMagneticFieldChanged(event);
                    break;
                case Sensor.TYPE_GRAVITY:
                    onGravityChanged(event);
                    break;
                case Sensor.TYPE_GYROSCOPE:
                    onGyroscopeChanged(event);
                    break;
                case Sensor.TYPE_PRESSURE:
                    onPressureChanged(event);
                    break;
                case Sensor.TYPE_STEP_COUNTER:
                    onStepsChange(event);
                    break;
                case Sensor.TYPE_ORIENTATION:
                    onOrientationChange(event);
                    break;
                case Sensor.TYPE_STEP_DETECTOR:
                    if (event.values[0] == 1.0) {
                        steps++;
                    }
                    break;
            }
            stepText.setText(String.valueOf(steps));
        }

        /**
         * 传感器精度改变时调用此方法
         * @param sensor 传感器实例
         * @param accuracy 精度
         */
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }
    };

//    /**
//     * 根据用户选择的方向计算方向坐标参数值
//     * 解释代码：https://blog.csdn.net/u014702999/article/details/51483361
//     * @return 判断的设备朝向结果
//     */
//    private String getOrientationFromRadioGroup() {
//        String direction="";
//        float Rien[] = new float[9];
//        float Inl[] = new float[9];
//        SensorManager.getRotationMatrix(Rien, Inl, gravity, geomagnetic);
//        SensorManager.getOrientation(Rien, orientation_values);
//
//        switch(orientGroup.getCheckedRadioButtonId()) {
//            case R.id.o_north:
//                orientation_values[0] = (float) 0.00001;
//                direction = "North";
//                break;
//            case R.id.o_east:
//                orientation_values[0] = (float) (Math.PI / 2);
//                direction = "East";
//                break;
//            case R.id.o_south:
//                orientation_values[0] = (float) (Math.PI);
//                direction = "South";
//                break;
//            case R.id.o_west:
//                orientation_values[0] = (float) (Math.PI*3.0 / 2);
//                direction = "West";
//                break;
//
//        }
//        //此处交换
//        float temp = orientation_values[0];
//        orientation_values[0] = orientation_values[1];
//        orientation_values[1] = orientation_values[2];
//        orientation_values[2] = temp;
//        return direction;
//    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start_record:
                if (actionEdit.getText().toString().length() != 0 ||
                        typeEdit.getText().toString().length() != 0) {
                    startRecord();
                } else {
                    Toast.makeText(this, "请输入动作", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.stop_record:
                stopRecord();
                break;
            case R.id.info_submit:
                // TODO: 2020/9/2 将数据传输到下一个页面
                Intent intent = new Intent(this, DataAnalysisActivity.class);
                intent.putExtra("path", fileName);
                startActivity(intent);
                break;
            case R.id.show_all_sensors:
                showDialog();
                break;
        }
    }

    /**
     * 传感器重力改变时调用此方法
     * @param event 传感器实例
     */
    private void onGravityChanged(SensorEvent event) {
        System.arraycopy(event.values, 0, gravity, 0, 3);
        gravityStartFlag = true;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < event.values.length; i++) {
            builder.append(event.values[i]).append(",");
        }
        builder.append(timestamp);
        FileRecord.record(fileName + "/gravity.txt",builder.toString() + "\r\n");
    }

    private void onOrientationChange(SensorEvent event) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < event.values.length; i++) {
            builder.append(event.values[i]).append(",");
        }
        builder.append(timestamp);
        FileRecord.record(fileName + "/orientation.txt",
                builder.toString() + "\r\n");
    }


    /**
     * 传感器磁场改变时调用此方法
     * @param event 传感器实例
     */
    private void onMagneticFieldChanged(SensorEvent event) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < event.values.length; i++) {
            builder.append(event.values[i]).append(",");
        }
        magneticText.setText(builder.toString());
        builder.append(timestamp);
        FileRecord.record(fileName + "/magnetic.txt",
                builder.toString() + "\r\n");
        for (int i = 0; i < 3; i++) {
            geomagnetic[i] = event.values[i];
        }
        recordMagneticAfterCST();
        if (gravity != null) {
            float[] r = new float[9];
            float[] I = new float[9];
            if (SensorManager.getRotationMatrix(r, I, gravity, geomagnetic)) {
                float h= (I[3]*r[0]+I[4]*r[3]+I[5]*r[6])*geomagnetic[0]+
                        (I[3]*r[1]+I[4]*r[4]+I[5]*r[7])*geomagnetic[1]+
                        (I[3]*r[2]+I[4]*r[5]+I[5]*r[8])*geomagnetic[2];
                magneticMagnitude.setText(String.valueOf(h));
                builder = new StringBuilder();
                builder.append(h).append(",");
                builder.append(timestamp);
                FileRecord.record(fileName + "/magnetic_magnitude.txt", builder.toString()+ "\r\n");
            }
        }
    }

    private void recordMagneticAfterCST() {

        float omegaMagnitude = (float) Math.sqrt(orientation_values[0] * orientation_values[0]
                + orientation_values[1] * orientation_values[1]
                + orientation_values[2] * orientation_values[2]);
        Matrix newGeoMag = CoordinateSystemRotation
                .coorinateSystemRotate(orientation_values, omegaMagnitude, geomagnetic);
        StringBuilder info=new StringBuilder();
        for(int i=0;i<3;i++) {
            info.append((float) newGeoMag.getArray()[i][0]).append(",");
        }
        info.append(timestamp);//.append(direction+"\t").append(xValue.getText()+"\t").append(yValue.getText()+"\t");
        FileRecord.record(fileName+"/magnetic_geo.txt", info.toString()+"\r\n");
    }

    /**
     * 传感器加速度改变时调用此方法
     * @param event 传感器实例
     */
    private void onAccelerationChanged(SensorEvent event) {
        StringBuilder info=new StringBuilder();
        for (int i = 0; i < 3; i++) {
            info.append(event.values[i]).append(",");
        }
        accelerationText.setText(info);
        float[] saveAc = new float[3];
        for (int i = 0; i < 3; i++) {
            saveAc[i] = event.values[i];
        }
        float[] valuesCompute=new float[3];
        float[] AngleValues=new float[3];
        float[] r=new float[9];
        float[] i=new float[9];
        SensorManager.getRotationMatrix(r, i, saveAc, geomagnetic);
        SensorManager.getOrientation(r, valuesCompute);
        for (int j = 0; j < 3; j++) {
            AngleValues[j] = (float) Math.toDegrees(valuesCompute[j]);
            info.append(AngleValues[j]).append(",");
        }
        directionText.setText("X:"+AngleValues[0]+"\n"+"Y:"+AngleValues[1]+"\n"+"Z:"+AngleValues[2]+"\n");
        info.append(timestamp);
        FileRecord.record(fileName + "/acceleration.txt", info.toString() + "\r\n");

        gravityNew = (float) Math.sqrt(event.values[0] * event.values[0]
                + event.values[1] * event.values[1] + event.values[2] * event.values[2]);

//        detectorNewStep(gravityNew);
    }

    /**
     * 传感器陀螺仪改变时调用此方法
     * @param event 传感器实例
     */
    private void onGyroscopeChanged(SensorEvent event){
        StringBuilder info=new StringBuilder();
        for (int i = 0; i < event.values.length; i++) {
            info.append(event.values[i]).append(",");
        }
        gyroText.setText(info.toString());
        info.append(timestamp);
        FileRecord.record(fileName+"/gyroscope.txt",info.toString()+"\r\n");
    }

    private void onPressureChanged(SensorEvent event) {
        StringBuilder pressure = new StringBuilder();
        for (int i = 0; i < event.values.length; i++) {
            pressure.append(event.values[i]).append(",");
        }
        pressureText.setText(pressure.toString());
        pressure.append(timestamp);
        FileRecord.record(fileName + "/pressure.txt", pressure.toString() + "\r\n");
    }

    private void onStepsChange(SensorEvent event) {
        int tempStep = (int) event.values[0];
        if (!hasRecoed) {
            hasRecoed = true;
            hasStepCount = tempStep;
        } else {
            int thisStepCount = tempStep - hasStepCount;
            int thisStep = thisStepCount - previousStepCount;
            steps = steps + thisStep;
            previousStepCount = thisStepCount;
        }
    }

    /**
     * 显示所有的传感器对话框
     */
    private void showDialog() {
        View view = LayoutInflater.from(this).inflate(R.layout.sensor_check, null, false);
        final AlertDialog dialog = new AlertDialog.Builder(this).setView(view).create();
        ListView listView = view.findViewById(R.id.lv);
        List<Sensor> deviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        ArrayList<String> mSensorList = new ArrayList<>();
        for (int i = 0; i < deviceSensors.size(); i++) {
            mSensorList.add(deviceSensors.get(i).getName());
        }
        ArrayAdapter<String> mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mSensorList);
        listView.setAdapter(mAdapter);
        Button button = view.findViewById(R.id.dialog_ok);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        dialog.show();
    }

    private void startRecord() {
        if (mTimer == null) {
            mTimer = new Timer();
        }
        String info = typeEdit.getText().toString() + "-" + actionEdit.getText().toString() + "-";
        Date now = new Date();
        DateFormat df = new DateFormat();
        fileName = folder + "/" + info
                + df.format("yyyy-MM-dd_hh-mm-ss", now);
        FileOperator.directMakeDir(fileName);
        //如果设备支持传感器，则为程序注册加速度传感器以及磁场传感器
        if (magneticSensor == null) {
            magneticText.setText("设备无磁场传感器");
        } else {
            mSensorManager.registerListener(mSensorEventListener, magneticSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        if (accelerometerSensor == null) {
            accelerationText.setText("设备无加速地传感器");
        } else {
            mSensorManager.registerListener(mSensorEventListener, accelerometerSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
            mSensorManager.registerListener(mSensorEventListener, gravitySensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        if (pressureSensor == null) {
            pressureText.setText("设备无气压传感器");
        } else {
            mSensorManager.registerListener(mSensorEventListener, pressureSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        if (stepSensor == null) {
            stepText.setText("设备无计步传感器");
        } else {
            mSensorManager.registerListener(mSensorEventListener, stepSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
            mSensorManager.registerListener(mSensorEventListener, detectSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        if (gyroscopeSensor == null) {
            gyroText.setText("设备无陀螺仪传感器");
        } else {
            mSensorManager.registerListener(mSensorEventListener, gyroscopeSensor,
                    SensorManager.SENSOR_DELAY_FASTEST);
        }
        mSensorManager.registerListener(mSensorEventListener, orienSensor,
                SensorManager.SENSOR_DELAY_FASTEST);
//        direction = getOrientationFromRadioGroup();
//        String getX = xEdit.getText().toString();
//        String getY=  yEdit.getText().toString();
//                String info = direction + "," + getX + "," + getY;
//                FileRecord.record(fileName +"/magnetic.txt",info +"\r\n");
//                FileRecord.record(fileName +"/magnetic_geo.txt",info +"\r\n");
//                FileRecord.record(fileName +"/gyroscope.txt",info +"\r\n");
//                FileRecord.record(fileName +"/acceleration.txt",info +"\r\n");
//                FileRecord.record(fileName + "/pressure.txt", info+ "\r\n");
//                FileRecord.record(fileName + "/gravity.txt", info+ "\r\n");
        startButton.setEnabled(false);
        stopButton.setEnabled(true);

        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();
                message.what = 1;
                mHandler.sendMessage(message);
            }
        };
        mTimer.schedule(mTimerTask, 0, 1000);
    }

    private void stopRecord() {
        mSensorManager.unregisterListener(mSensorEventListener);
        if (mTimerTask != null) {
            mTimerTask.cancel();
        }
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        showInputDialog();
    }

    /**
     * 重写音量键事件
     * @param keyCode 音量键上下键代码
     * @param event 音量键点击事件
     * @return 是否点击
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            stopRecord();
        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            if (actionEdit.getText().toString().length() != 0) {
                startRecord();
            } else {
                Toast.makeText(this, "请输入动作", Toast.LENGTH_SHORT).show();
            }
        }
        return false;
    }

    private void showInputDialog() {
        final EditText inputText = new EditText(this);
        inputText.setText(fileName);
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("确认路径").setView(inputText)
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        newPath = inputText.getText().toString();
                        if (FileOperator.renameFile(fileName, newPath)) {
                            Toast.makeText(MainActivity.this, "success", Toast.LENGTH_SHORT).show();
                        }

                    }
                });
        builder.show();
    }
}
